/**
 * 针对S2500跨路内存访问测试
 * @file crossCpuMemoryTest.c
 * @author yeqiang@greatwall.com.cn
 * @brief
 * @version 0.1
 * @date 2022-08-22
 *
 * @copyright Copyright (c) 2022
 *
 */
#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <sched.h>
#include <errno.h>
#include <pthread.h>

// GB
#define BUFF_SIZE (1.9 * 1024 * 1024 * 1024l)
#define BLOCK_SIZE (1024 * 1024)

/* Return the UNIX time in microseconds */
long long ustime(void)
{
    struct timeval tv;
    long long ust;

    gettimeofday(&tv, NULL);
    ust = ((long long)tv.tv_sec) * 1000000;
    ust += tv.tv_usec;
    return ust;
}

void *memoryTest(void *arg)
{
    int *p = (int *)arg;
    int i = *p;
    while (1)
    {
        printf("Core%d\n", i);
        cpu_set_t mask;
        CPU_ZERO(&mask);
        CPU_SET(i, &mask);
        // 进程迁移到Core i
        if (sched_setaffinity(0, sizeof(mask), &mask) == -1)
        {
            printf("绑定CPU出错, ERROR:%s\n", strerror(errno));
            return NULL;
        }
        printf("Core%d(node%d)\n", i, i / 8);
        fflush(stdout);
        // 申请内存
        char *srcBuff = (char *)malloc(BUFF_SIZE);
        printf("malloc\n");
        fflush(stdout);
        // 设置内存值
        int block = BUFF_SIZE / BLOCK_SIZE;
        for (unsigned long t = 0; t < block; t++)
        {
            memset(srcBuff + t * BLOCK_SIZE, t, BLOCK_SIZE);
        }
        printf("memset\n");
        fflush(stdout);
        //进程迁移到 Core i+64
        int newCoreId = i < 64 ? i + 64 : i - 64;
        CPU_ZERO(&mask);
        CPU_SET(newCoreId, &mask);
        printf("迁移到 Core%d(node%d)\n", newCoreId, newCoreId / 8);
        fflush(stdout);
        // 进程迁移到Core i
        if (sched_setaffinity(0, sizeof(mask), &mask) == -1)
        {
            printf("绑定CPU出错, ERROR:%s\n", strerror(errno));
            return NULL;
        }
        char *destBuff = (char *)malloc(BUFF_SIZE);
        printf("malloc\n");
        fflush(stdout);
        int tmp = 1;

        // 跨路 从Core i 复制对应内存数据到 Core i+64
        memcpy(destBuff, srcBuff, BUFF_SIZE);
        printf("memcpy\n");
        fflush(stdout);
        // 重置destBuff
        memset(destBuff, tmp++, BUFF_SIZE);
        for (unsigned long t = 0; t < block; t++)
        {
            memset(destBuff + t * BLOCK_SIZE, t + 1, BLOCK_SIZE);
        }
        printf("memset2\n");
        fflush(stdout);
        // 反向复制一次
        memcpy(srcBuff, destBuff, BUFF_SIZE);
        printf("memcpy(反向)\n");
        fflush(stdout);

        //迁移回Core i
        CPU_ZERO(&mask);
        CPU_SET(i, &mask);
        printf("返回 Core%d(node%d)\n", i, i / 8);
        fflush(stdout);
        // 进程迁移到Core i
        if (sched_setaffinity(0, sizeof(mask), &mask) == -1)
        {
            printf("绑定CPU出错, ERROR:%s\n", strerror(errno));
            return NULL;
        }

        // 跨路 从Core i 复制对应内存数据到 Core i+64
        memcpy(destBuff, srcBuff, BUFF_SIZE);
        printf("memcpy3\n");
        fflush(stdout);
        // 重置destBuff
        memset(destBuff, tmp++, BUFF_SIZE);
        for (unsigned long t = 0; t < block; t++)
        {
            memset(destBuff + t * BLOCK_SIZE, t + 1, BLOCK_SIZE);
        }
        printf("memset3\n");
        fflush(stdout);
        // 反向复制一次
        memcpy(srcBuff, destBuff, BUFF_SIZE);
        printf("memcpy3(反向)\n");
        fflush(stdout);

        free(srcBuff);
        free(destBuff);
        printf("free\n");
        i++;
        if (i >= 127)
        {
            i = 0;
        }
    }
    return NULL;
}

pthread_mutex_t locks[128];
unsigned long counter = 0;

void *lockTest(void *arg)
{
    int *p = (int *)arg;
    int id = *p;
    while (1)
    {
        cpu_set_t mask;
        CPU_ZERO(&mask);
        CPU_SET(id, &mask);
        // 进程迁移到Core i
        if (sched_setaffinity(0, sizeof(mask), &mask) == -1)
        {
            printf("绑定CPU出错, ERROR:%s\n", strerror(errno));
            return NULL;
        }
        printf("start lockTest %d, at Core%d\n", id, id);
        for (int i = 0; i < 1000000; i++)
        {
            for (int j = 0; j < 128; j++)
            {
                pthread_mutex_lock(&locks[j]);
                counter++;
                pthread_mutex_unlock(&locks[j]);
            }
        }
        printf("finish lockTest %d\n", id);
        id++;
        if (id >= 127)
        {
            id = 0;
        }
    }
    return NULL;
}

int main(int argc, char *argv[])
{
    pid_t pid = getpid();
    printf("pid=%d\n", pid);

    int cpuid = 0;
    pthread_t threads[128];
    pthread_t lockThreads[128];
    int param[128];

    for (int i = 0; i < 128; i++)
    {
        param[i] = i;
        pthread_mutex_init(&locks[i], NULL);
        int err = pthread_create(&threads[i], NULL, memoryTest, &param[i]);
        if (err != 0)
        {
            printf("memoryTest线程创建失败\n");
        }
        err = pthread_create(&lockThreads[i], NULL, lockTest, &param[i]);
        if (err != 0)
        {
            printf("lockTest线程创建失败\n");
        }
    }
    for (int i = 0; i < 128; i++)
    {
        pthread_join(threads[i], NULL);
        pthread_join(lockThreads[i], NULL);
    }

    return 0;
}